/*
 * Copyright 2010 - 2011, The PLDesktop Development Team
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 *
 */

#ifndef PLMACHINE_H
#define PLMACHINE_H

#include <stddef.h>
#include <bootstrapinfo.h>
#include <commandline.h>
#include <plconfig.h>
#include <kernelelf.h>
#include <lib/tar.h>
#include <lib/modulehandler.h>
#include <initrd/initrd.h>
#include <machine/pc/memory/virtualpagemanager.h>
#include <machine/pc/memory/memmanager.h>

#include <tools/PLFlags.h>
#include <tools/PLSingleton.h>
using namespace PLSDK;

/**
 * The base class for a machine that uses the machine interface to access
 * functions from the machines.
 */
class PLMachine : public PLSingleton<PLMachine> {
	friend class PLSingleton<PLMachine>;
public:
	/**
	 * The loaded features of the system.
	 */
	enum LoadStateEnum {
		/**
		 * Is the memory management activ.
		 */
		MemManagementLoaded			= 1 << 1
	};
	PLDECLAREFLAGS(LoadState, LoadStateEnum);
public:
	/**
	 * Set the multiboot address and read the information.
	 *
	 * @param address The address of the multiboot information.
	 * @todo implement a 64 bit version too.
	 */
	void setMultiboot(unsigned long address);
	/**
	 * The commandline parser was created and the memory map was
	 * read and set.
	 */
	void readMultibootInformtion();
	/**
	 * Get the multiboot information.
	 *
	 * @return The multiboot information.
	 */
	inline Multiboot_info *multibootInfo();
	/**
	 * Start the mashine.
	 */
	void start();
	/**
	 * Add a new loaded state to the loaded states.
	 *
	 * @param state The state to add.
	 */
	void addState(LoadStateEnum state);
	/**
	 * Test for a state that it was loaded.
	 *
	 * @param state The state to test.
	 */
	bool testState(LoadStateEnum state);
	/**
	 * The number of processors in the machine.
	 */
	inline size_t processorCount();
	/**
	 * Get the kernel commandline.
	 *
	 * @return The kernel commandline.
	 */
	PLCommandline *kernelCommandline();
	/**
	 * Get the virtual page manager for the kernel memory.
	 *
	 * @return The virtual page manager.
	 */
	inline PLVirtualPageManager *kernelVirtualPageManager();
	/**
	 * Get the kernel memory manager to allocate memory.
	 *
	 * @return The kernel memory manager.
	 */
	inline PLMemManager *kernelMemManger();
    /**
     * Get the information from the kernel.
     *
     * @return The elf information.
     */
    inline KernelElf *kernelElfInformation();
    /**
     * Get the initrd tar archive from the system.
     *
     * @return The initrd archive.
     */
    inline Tar *initrdArchive();
protected:
	/**
	 * Constructor.
	 */
	PLMachine();
private:
	void initKernelElf();
    void initModuleInformation();
	LoadState m_state;
	size_t m_processorCount;
	Multiboot_info *m_bootInfo;
	PLCommandline *m_commandline;
	PLVirtualPageManager *m_kernelVirtualManager;
	PLMemManager m_kernelMemManger;
	KernelElf *m_kernelElf;
    ModuleHandler *m_moduleHandler;
    Tar *m_initrdArchive;
    InitRD *m_initrd;
};

size_t PLMachine::processorCount() {
	return m_processorCount;
}

PLVirtualPageManager *PLMachine::kernelVirtualPageManager() {
	return m_kernelVirtualManager;
}

PLMemManager *PLMachine::kernelMemManger() {
	return &m_kernelMemManger;
}

KernelElf *PLMachine::kernelElfInformation() {
    return m_kernelElf;
}

Multiboot_info *PLMachine::multibootInfo() {
	return m_bootInfo;
}

Tar *PLMachine::initrdArchive() {
    return m_initrdArchive;
}

#endif // PLMACHINE_H
